/*--------------------------------------------------------------------------------
* Copyright (c) 2022,西北农林科技大学信息学院计算机科学系
* All rights reserved.
*
* 文件名称：main.c
* 文件标识：见配置管理计划书
* 摘要：检查单词是否为变位词(相同字母的重新排列)的演示代码。
* 题目：在英语中，如果两个单词中出现的字母相同，
*       并且每个字符出现的次数也相同，
*       那么这两个单词互为变位词(Anagram)。例如：
*       slient与listen、evil与live等互为变位词。
*
* 当前版本：1.0
* 作者：耿楠
* 完成日期：2022年12月06日
*
* 取代版本：无
* 原作者：
* 完成日期：
--------------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* 函数原型 */
int is_anagram(const char *, const char *); /* 检查单词是否为变位词(映射数组算法) */
int is_word(const char *);
long get_check(const char *);
void test(char **, char **, size_t n);

int main()
{
    char *p[] = {"listen", "alient", "Live", "Livie", "eil", "evil1"};
    char *q[] = {"slient", "listen", "eviL", "eeviL", "live", "live1"};

    test(p, q, 6);

    return 0;
}

void test(char **p, char **q, size_t n)
{
    int i, ret;

    for(i = 0; i < n; i++)
    {
        ret = is_anagram(p[i], q[i]);

        if(ret)
        {
            printf("%s and %s is angram.\n", p[i], q[i]);
        }
        else
        {
            printf("%s and %s is not angram.\n", p[i], q[i]);
        }
    }
}

/*-------------------------------------------------------------------------------------
// 名称: int is_word(const char *s)
// 功能: 检查一个字符串是否为单词
// 参数:
//       [const char *str1] --- 指向字符串的指针
// 返回: [int]  --- 1表示是变位词，0表示不是变位词
// 作者: 耿楠
// 日期: 2018年12月07日
//-------------------------------------------------------------------------------------*/
int is_word(const char *s)
{
    while(*s)
    {
        if(!((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z')))
        {
            return 0;
        }
        s++;
    }

    return 1;
}

/*-------------------------------------------------------------------------------------
// 名称: long get_check(const char *str)
// 功能: 获得一个字符串的检验码
// 算法: 用一个long整数各个位记录构成单词的每一个字母的状态。
//       将1左移n位，相当于得到2^n，然后对其求和得到检验码。
// 参数:
//       [const char *str1] --- 指向单词的指针
// 返回: [long] --- 检验码
// 作者: 李建良 耿楠
// 日期: 2022年12月06日
//-------------------------------------------------------------------------------------*/
long get_check(const char *str)
{
    int i , key;
    long A = 0L;

    for(i = 0; str[i] != '\0'; i++)
    {
        if ((str[i] > 'a') && (str[i] < 'z'))
        {
            /* 小写字母的移位量 */
            key = str[i] - 'a' + 26;
        }
        else
        {
            /* 大写字母的移位量 */
            key = str[i] - 'A';
        }

        /* 构造检验码 */
        A += 1 << key;
    }

    return A;
}

/*-------------------------------------------------------------------------------------
// 名称: int is_anagram(const char *str1, const char *str2)
// 功能: 检查两个单词是否为变位词(相同字母的重新排列)
// 算法: 用一个long整数检验码各个位记录构成单词的每一个字母的状态，
//       最后用异或操作判断两个字符串的检验码是否相同。
// 注意: 如果两个字符串长度不相等，则一定不是变位词。
//       如果字符串中含有非字母字符也一定不是变位词。
// 参数:
//       [const char *str1] --- 指向第1个单词的指针
//       [const char *str2] --- 指向第2个单词的指针
// 返回: [int]  --- 1表示是变位词，0表示不是变位词
// 作者: 李建良 耿楠
// 日期: 2022年12月06日
//-------------------------------------------------------------------------------------*/
int is_anagram(const char *str1, const char *str2)
{
    long A1 = 0L, B1 = 0L;
    size_t len1 = strlen(str1);
    size_t len2 = strlen(str2);

    /* 字符串指针为空 */
    if(str1 == NULL || str2 == NULL)
    {
        return 0;
    }

    /* 如果长度不等，或不是单词 */
    if(len1 != len2 || !is_word(str1) || !is_word(str2))
    {
        return 0;
    }

    /* 计算两个字符串的检验码 */
    A1 = get_check(str1);
    B1 = get_check(str2);

    /* 判断结果 */
    return !(A1 ^ B1);
}
